/* eslint-disable no-new */
/* eslint-disable no-undef */
class Vue {
  constructor (options) {
    this.$options = options || {}
    this.data = this.$options.data || {}
    this.computed = this.$options.computed || {}
    this.methods = this.$options.methods || {}
    // 1.1 proxy data's propperty: vm.data.xxx -> vm.xxx
    Object.keys(this.data).forEach((key) => {
      this.proxyKeys(key)
    })
    // 1.2 计算属性
    Object.keys(this.computed).forEach((key) => {
      this.proxyKeys(key)
    })
    // 1.3 proxy data's methods: vm.methds.xxx -> vm.xxx
    Object.keys(this.methods).forEach((key) => {
      this.proxyKeys(key)
    })
    // 2.1 definReactive: 劫持所有属性，通知发布者属性的变化，发布者通知所有dependence(Dep)
    observer(this.data)
    // 2.2 监听computed
    observer(this.computed, this)
    // 3. compile 编译节点，所有依赖（watcher）的收集在此步骤进行
    new Compile(options.el, this)
    // 4. mounted: 编译初始化完毕，包含所有节点的文档碎片已成功挂载到根节点，vue实例化完毕
    // 代码健壮性处理
    typeof options.mounted === 'function' && options.mounted.call(this)
  }
  proxyKeys (key) {
    Object.defineProperty(this, key, {
      enumerable: true,
      configurable: false,
      get: function () {
        return this.data[key] !== undefined
          ? this.data[key] : this.computed[key] !== undefined
            ? this.computed[key] : this.methods[key]
      },
      set: function (newVal) {
        this.data[key] !== undefined
          ? this.data[key] = newVal : this.computed[key] !== undefined
            ? this.computed[key] = newVal : this.methods[key] = newVal
      }
    })
  }
}

(function () {
  return Vue
})()
